package com.kexilo.core.common.utils;

import org.apache.commons.lang3.time.DateFormatUtils;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoUnit;
import java.util.Date;

/**
 * 时间工具类
 * 
 * @author Kexilo
 */
public class DateUtils {

    public static final String YYYY = "yyyy";

    public static final String YYYY_MM = "yyyy-MM";

    public static final String YYYY_MM_DD = "yyyy-MM-dd";

    public static final String YYYYMMDDHHMMSS = "yyyyMMddHHmmss";

    public static final String YYYY_MM_DD_HH_MM_SS = "yyyy-MM-dd HH:mm:ss";

    private static final String[] PARSE_PATTERNS = {
            "yyyy-MM-dd", "yyyy-MM-dd HH:mm:ss", "yyyy-MM-dd HH:mm", "yyyy-MM",
            "yyyy/MM/dd", "yyyy/MM/dd HH:mm:ss", "yyyy/MM/dd HH:mm", "yyyy/MM",
            "yyyy.MM.dd", "yyyy.MM.dd HH:mm:ss", "yyyy.MM.dd HH:mm", "yyyy.MM"};

    /**
     * 获取当前Date型日期
     * 
     * @return Date() 当前日期
     */
    public static Date getNowDate() {
        return new Date();
    }

    /**
     * 获取当前LocalDateTime
     * 
     * @return LocalDateTime 当前日期时间
     */
    public static LocalDateTime getNow() {
        return LocalDateTime.now();
    }

    /**
     * 获取当前LocalDate
     * 
     * @return LocalDate 当前日期
     */
    public static LocalDate getToday() {
        return LocalDate.now();
    }

    /**
     * 获取当前日期字符串, 格式(yyyy-MM-dd)
     * 
     * @return String
     */
    public static String getDate() {
        return getToday().format(DateTimeFormatter.ofPattern(YYYY_MM_DD));
    }

    /**
     * 获取当前时间字符串, 格式(yyyy-MM-dd HH:mm:ss)
     * 
     * @return String
     */
    public static String getTime() {
        return getNow().format(DateTimeFormatter.ofPattern(YYYY_MM_DD_HH_MM_SS));
    }

    /**
     * 获取当前日期, 默认格式(yyyy-MM-dd HH:mm:ss)
     * 
     * @return String
     */
    public static String dateTimeNow() {
        return dateTimeNow(YYYY_MM_DD_HH_MM_SS);
    }

    /**
     * 获取当前日期, 指定格式
     * 
     * @param format 格式
     * @return String
     */
    public static String dateTimeNow(final String format) {
        return getNow().format(DateTimeFormatter.ofPattern(format));
    }

    /**
     * 获取当前日期, 默认格式(yyyy-MM-dd)
     * 
     * @return String
     */
    public static String dateNow() {
        return dateNow(YYYY_MM_DD);
    }

    /**
     * 获取当前日期, 指定格式
     * 
     * @param format 格式
     * @return String
     */
    public static String dateNow(final String format) {
        return getToday().format(DateTimeFormatter.ofPattern(format));
    }

    /**
     * 日期转字符串格式
     * 
     * @param date 日期
     * @return 日期字符串 yyyy-MM-dd
     */
    public static String formatDate(Date date) {
        return formatDate(date, YYYY_MM_DD);
    }

    /**
     * 日期转字符串格式
     * 
     * @param date 日期
     * @param pattern 格式
     * @return 日期字符串
     */
    public static String formatDate(Date date, String pattern) {
        if (date == null) {
            return null;
        }
        LocalDateTime localDateTime = date.toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime();
        return localDateTime.format(DateTimeFormatter.ofPattern(pattern));
    }

    /**
     * LocalDateTime转字符串格式
     * 
     * @param localDateTime 时间
     * @return 日期字符串 yyyy-MM-dd HH:mm:ss
     */
    public static String formatDateTime(LocalDateTime localDateTime) {
        return formatDateTime(localDateTime, YYYY_MM_DD_HH_MM_SS);
    }

    /**
     * LocalDateTime转字符串格式
     * 
     * @param localDateTime 时间
     * @param pattern 格式
     * @return 日期字符串
     */
    public static String formatDateTime(LocalDateTime localDateTime, String pattern) {
        if (localDateTime == null) {
            return null;
        }
        return localDateTime.format(DateTimeFormatter.ofPattern(pattern));
    }

    /**
     * LocalDate转字符串格式
     * 
     * @param localDate 日期
     * @return 日期字符串 yyyy-MM-dd
     */
    public static String formatDate(LocalDate localDate) {
        return formatDate(localDate, YYYY_MM_DD);
    }

    /**
     * LocalDate转字符串格式
     * 
     * @param localDate 日期
     * @param pattern 格式
     * @return 日期字符串
     */
    public static String formatDate(LocalDate localDate, String pattern) {
        if (localDate == null) {
            return null;
        }
        return localDate.format(DateTimeFormatter.ofPattern(pattern));
    }

    /**
     * 字符串转Date
     * 
     * @param str 字符串
     * @return Date
     */
    public static Date parseDate(String str) {
        if (str == null) {
            return null;
        }
        try {
            return parseLocalDateTime(str).atZone(ZoneId.systemDefault()).toInstant().toEpochMilli() > 0 ?
                    Date.from(parseLocalDateTime(str).atZone(ZoneId.systemDefault()).toInstant()) : null;
        } catch (Exception e) {
            return null;
        }
    }

    /**
     * 字符串转LocalDateTime
     * 
     * @param str 字符串
     * @return LocalDateTime
     */
    public static LocalDateTime parseLocalDateTime(String str) {
        if (StringUtils.isEmpty(str)) {
            return null;
        }
        
        // 尝试不同的格式进行解析
        for (String pattern : PARSE_PATTERNS) {
            try {
                DateTimeFormatter formatter = DateTimeFormatter.ofPattern(pattern);
                if (pattern.contains("HH")) {
                    return LocalDateTime.parse(str, formatter);
                } else {
                    return LocalDate.parse(str, formatter).atStartOfDay();
                }
            } catch (Exception e) {
                // 继续尝试下一个格式
            }
        }
        
        throw new IllegalArgumentException("无法解析日期字符串: " + str);
    }

    /**
     * 字符串转LocalDate
     * 
     * @param str 字符串
     * @return LocalDate
     */
    public static LocalDate parseLocalDate(String str) {
        if (StringUtils.isEmpty(str)) {
            return null;
        }
        
        try {
            return LocalDate.parse(str, DateTimeFormatter.ofPattern(YYYY_MM_DD));
        } catch (Exception e) {
            // 尝试其他格式
            for (String pattern : PARSE_PATTERNS) {
                if (!pattern.contains("HH")) {
                    try {
                        return LocalDate.parse(str, DateTimeFormatter.ofPattern(pattern));
                    } catch (Exception ex) {
                        // 继续尝试
                    }
                }
            }
        }
        
        throw new IllegalArgumentException("无法解析日期字符串: " + str);
    }

    /**
     * 获取服务器启动时间
     */
    public static Date getServerStartDate() {
        long time = java.lang.management.ManagementFactory.getRuntimeMXBean().getStartTime();
        return new Date(time);
    }

    /**
     * 日期路径 即年/月/日 如2018/08/08
     */
    public static final String datePath() {
        Date now = new Date();
        return DateFormatUtils.format(now, "yyyy/MM/dd");
    }

    /**
     * 时间路径 即年/月/日 如20180808
     */
    public static final String dateTime() {
        Date now = new Date();
        return DateFormatUtils.format(now, "yyyyMMdd");
    }

    /**
     * 计算相差天数
     */
    public static int differentDaysByMillisecond(Date date1, Date date2) {
        return Math.abs((int) ((date2.getTime() - date1.getTime()) / (1000 * 3600 * 24)));
    }

    /**
     * 计算LocalDate相差天数
     */
    public static long differentDays(LocalDate date1, LocalDate date2) {
        return Math.abs(ChronoUnit.DAYS.between(date1, date2));
    }

    /**
     * 计算LocalDateTime相差小时数
     */
    public static long differentHours(LocalDateTime dateTime1, LocalDateTime dateTime2) {
        return Math.abs(ChronoUnit.HOURS.between(dateTime1, dateTime2));
    }

    /**
     * 计算LocalDateTime相差分钟数
     */
    public static long differentMinutes(LocalDateTime dateTime1, LocalDateTime dateTime2) {
        return Math.abs(ChronoUnit.MINUTES.between(dateTime1, dateTime2));
    }

    /**
     * 获取某天的开始时间
     */
    public static LocalDateTime getDayStart(LocalDate date) {
        return LocalDateTime.of(date, LocalTime.MIN);
    }

    /**
     * 获取某天的结束时间
     */
    public static LocalDateTime getDayEnd(LocalDate date) {
        return LocalDateTime.of(date, LocalTime.MAX);
    }

    /**
     * 获取当前月的第一天
     */
    public static LocalDate getFirstDayOfMonth() {
        return getToday().withDayOfMonth(1);
    }

    /**
     * 获取当前月的最后一天
     */
    public static LocalDate getLastDayOfMonth() {
        return getToday().withDayOfMonth(getToday().lengthOfMonth());
    }

    /**
     * 判断是否是今天
     */
    public static boolean isToday(LocalDate date) {
        return getToday().equals(date);
    }

    /**
     * 判断是否是今天
     */
    public static boolean isToday(LocalDateTime dateTime) {
        return isToday(dateTime.toLocalDate());
    }

    /**
     * Date转LocalDateTime
     */
    public static LocalDateTime toLocalDateTime(Date date) {
        if (date == null) {
            return null;
        }
        return date.toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime();
    }

    /**
     * LocalDateTime转Date
     */
    public static Date toDate(LocalDateTime localDateTime) {
        if (localDateTime == null) {
            return null;
        }
        return Date.from(localDateTime.atZone(ZoneId.systemDefault()).toInstant());
    }

    /**
     * LocalDate转Date
     */
    public static Date toDate(LocalDate localDate) {
        if (localDate == null) {
            return null;
        }
        return Date.from(localDate.atStartOfDay(ZoneId.systemDefault()).toInstant());
    }
}


